package utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import org.junit.jupiter.api.Assertions;
import utils.MyException.HttpRequestException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class BaseHttp {
    private MyTestLogToTxt log = new MyTestLogToTxt();
    private GetJsonValue getJson = new GetJsonValue();
    private StringBuilder urlBuilder = new StringBuilder();
    private String response;
    private static CookieManager cookieManager = new CookieManager();
    private Map<String, List<String>> responseHeaders;

    public String getResponse() {
        return response;
    }

    public Map<String, List<String>> getResponseHeaders() {
        Map<String, List<String>> map = new HashMap<>();
        responseHeaders.forEach((k, v) -> {
            if (Optional.ofNullable(k).isPresent())
                map.put(k.toLowerCase(), v);
        });
        return map;
    }


    private HostnameVerifier hv = (urlHostName, session) -> {
        System.out.println("Warning: URL Host: " + urlHostName + " vs. "
                + session.getPeerHost());
        return true;
    };

    private static void trustAllHttpsCertificates() throws Exception {
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
                .getInstance("SSL", "SunJSSE");
        sc.init(null, new javax.net.ssl.TrustManager[]{new miTM()}, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc
                .getSocketFactory());
    }

    static class miTM implements javax.net.ssl.TrustManager,
            javax.net.ssl.X509TrustManager {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(
                java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(
                java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }
    }

    private void MapToString(Map<String, Object> params, StringBuilder urlBuilder) {
        if (null != params) {
            Iterator<Map.Entry<String, Object>> iterator = params.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> param = iterator.next();
                urlBuilder.append(URLEncoder.encode(param.getKey(), StandardCharsets.UTF_8)).append('=')
                        .append(URLEncoder.encode(param.getValue().toString(), StandardCharsets.UTF_8));
                if (iterator.hasNext()) {
                    urlBuilder.append('&');
                }
            }
        }
    }

    private HttpURLConnection request(String serverPath, Map<String, Object> params, Map<String, String> map_headers, String pathParams, String method) throws Exception {
        URL url;
        HttpURLConnection conn;

        if (!(urlBuilder.length() == 0))
            urlBuilder.delete(0, urlBuilder.length());

        if ("POST".equals(method) || "PUT".equals(method)) {
            url = new URL(serverPath);
            conn = (HttpURLConnection) url.openConnection();
            if (params != null) {
                MapToString(params, urlBuilder);
            }
            if (pathParams != null) {
                urlBuilder.append(pathParams);
            }
            setHttpcs(map_headers, method, conn);

            OutputStream os = conn.getOutputStream();
            os.write(urlBuilder.toString().getBytes());
            os.flush();
            os.close();
        } else {
            urlBuilder.append(serverPath);

            if (null != params) {

                urlBuilder.append("?");

                MapToString(params, urlBuilder);
            }

            url = new URL(urlBuilder.toString());
            conn = (HttpURLConnection) url.openConnection();
            setHttpcs(map_headers, method, conn);
        }
        return conn;
    }

    /**
     * http 请求
     *
     * @param serverPath  服务器地址+url
     * @param params      键值对参数
     * @param map_headers 请求头
     * @param method      请求方法
     * @return 响应参数
     */
    public BaseHttp HTTPConnection(String serverPath, Map<String, Object> params, Map<String, String> map_headers, String method) throws Exception {
        return HTTPConnection(serverPath, params, map_headers, null, method);
    }

    public BaseHttp HTTPConnection(String serverPath, String params, Map<String, String> map_headers, String method) throws Exception {
        return HTTPConnection(serverPath, null, map_headers, params, method);
    }

    public BaseHttp HTTPConnection(String serverPath, Map<String, String> map_headers, String method) throws Exception {
        return HTTPConnection(serverPath, null, map_headers, null, method);
    }

    public BaseHttp HTTPConnection(String serverPath, Map<String, Object> params, Map<String, String> map_headers, String pathParams, String method) throws Exception {

        CookieHandler.setDefault(cookieManager);
        cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);

        HttpURLConnection conn = request(serverPath, params, map_headers, pathParams, method);
        InputStream in;
        long startTime = new DateTime().getTime();

        if (conn.getResponseCode() == 200) {
            responseHeaders = conn.getHeaderFields();
            if (responseHeaders.containsKey("Content-Transfer-Encoding")
                    && responseHeaders.get("Content-Transfer-Encoding").toString().equals("[binary]")) {
                String fileName = URLDecoder.decode(responseHeaders.get("Content-Disposition").toString().replace("[attachment; filename=\"", "")
                        .replace("\"]", ""), StandardCharsets.UTF_8);
                File file = new File(fileName);

                Assertions.assertTrue(file.exists() || file.createNewFile());

                FileOutputStream fileOutputStream = new FileOutputStream(file);
                fileOutputStream.write(conn.getInputStream().readAllBytes());

                fileOutputStream.flush();
                fileOutputStream.close();
                response = "下载文件名称:" + fileName;
                return this;
            }
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));// 读取流缓冲区
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.close();
            String res;
            long Duration = new DateTime().getTime() - startTime;
            if (Duration > 2000) {
                System.err.println("请求耗时大于2s：" + Duration + "   " + serverPath);
            }
            try {
                res = new JSONObject(sb.toString()).toString();
                log.printLogs(Config.TESTNUMBER, serverPath,
                        urlBuilder.toString(), method, conn.getResponseCode(), res, String.valueOf(Duration));
            } catch (JSONException e) {
                res = sb.toString();
                log.printLogs(Config.TESTNUMBER, serverPath,
                        urlBuilder.toString(), method, conn.getResponseCode(), res, String.valueOf(Duration));
                throw new JSONException("返回json数据格式不正确:" + res);
            }

            String ret = getJson.getCurrentValue(res, "ret");


            if (!"0".equals(ret)) {
                throw new HttpRequestException("请求失败：" + res);
            }
            response = res;

        } else {
            System.out.println("doPost_login=" + conn.getResponseCode());
            in = conn.getErrorStream();// 读取错误流

            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder sb = new StringBuilder();

            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.close();
            long time = new DateTime().getTime() - startTime;
            if (time > 2000) {
                System.err.println("请求耗时大于2s：" + time + "   " + serverPath);
            }
            log.printLogs(Config.TESTNUMBER, serverPath,
                    urlBuilder.toString(),
                    "POST", conn.getResponseCode(), sb.toString(),
                    String.valueOf(time));

            throw new HttpRequestException("请求失败：" + sb.toString());
        }
        return this;

    }

    private void setHttpcs(Map<String, String> map_headers, String method, HttpURLConnection conn) throws Exception {
        conn.setRequestMethod(method);
        if (map_headers != null) {
            map_headers.forEach(conn::setRequestProperty);
        }
        trustAllHttpsCertificates();
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
        conn.setDoOutput(true);// 设置允许写出
        conn.setDoInput(true);// 设置允许写入
        conn.setUseCaches(false);
    }

}
